package startup.security.service.impl;

import cn.hutool.core.date.DateUtil;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;
import com.amazonaws.services.securitytoken.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import startup.security.service.S3FileManagerService;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * Description:
 *
 * @author: ly
 * @date:Created in 2023/03/02 13:50
 */
@Service
@Slf4j
public class S3FileManagerServiceImpl implements S3FileManagerService {

    private static String fileBucket;
    private static String awsAccessKey ;
    private static String awsSecretKey ;
    private static String endpoint;
    private static String signingRegion ;
    private static String enRole;
    private static AmazonS3Client amazonS3;

    static {
        try {
             fileBucket = "epc-dev";
             awsAccessKey = "AKIATBYC5AJG5LCBXX6A";
             awsSecretKey = "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";
             endpoint = "https://epc-dev.s3.cn-north-1.amazonaws.com.cn/";
             signingRegion = "cn-north-1";
             enRole="arn:aws-cn:iam::048354734562:role/R-DEV-EPC-DEVELOPER";


            AWSCredentials awsCredentials = new BasicAWSCredentials(awsAccessKey, awsSecretKey);
            AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.standard()
                    .withRegion(Regions.CN_NORTH_1)
                    .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
                    .build();

            AssumeRoleRequest roleRequest = new AssumeRoleRequest()
                    .withRoleArn(enRole)
                    .withRoleSessionName("...")
                    .withDurationSeconds(3600)
                    .withExternalId("...");


            AssumeRoleResult roleResponse = stsClient.assumeRole(roleRequest);
            BasicSessionCredentials basicSessionCredentials = new BasicSessionCredentials(roleResponse.getCredentials().getAccessKeyId(), roleResponse.getCredentials().getSecretAccessKey(),
                    roleResponse.getCredentials().getSessionToken());

            amazonS3 = (AmazonS3Client) AmazonS3ClientBuilder.standard()
                    .withCredentials(new AWSStaticCredentialsProvider(basicSessionCredentials))
                    .withRegion(Regions.CN_NORTH_1)
                    .build();

        } catch (Exception e) {
            log.error("amazonS3文件服务器基础参数加载出错" + e.getMessage());
        }
        log.info("amazonS3 文件服务器基础参数加载完成 access_key=" + awsAccessKey + " endpoint_url=" + endpoint);
    }


    @Override
    public void upload(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        if (fileName == null) {
            log.error("传入的文件名不能为空");
        }
        if (!this.validateFileName(fileName)) {
            log.error("文件名应仅包含汉字、字母、数字、下划线和点号");
        }

        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentType(file.getContentType());
        objectMetadata.setContentLength(file.getSize());

        /**
         * 文件表
         * filesize
         * fielname
         * fileOrgin
         * key
         */
        Date date = DateUtil.date();
        //上传文件上传到指定目录，s3没有文件夹的概念，只有url的概念，每天生成对应的url，方便归纳管理
        String format = DateUtil.format(date, "yyyyMMdd");
        String key = "pic/"+format+"/"+System.currentTimeMillis() + fileName;

        List<Bucket> buckets = amazonS3.listBuckets();
        /**
         * 获取桶列表对象
         */
        ListObjectsV2Result result = amazonS3.listObjectsV2(fileBucket);
        List<S3ObjectSummary> objects = result.getObjectSummaries();
        for (S3ObjectSummary os : objects) {
            System.out.println("桶列表对象* " + os.getKey()+"......="+os.getBucketName());
        }


        /**
         * 获取桶名称
         */
        System.out.println("Your {S3} buckets are:");
        for (Bucket b : buckets) {
            System.out.println("* " + b.getName());
        }

        /**
         * 文件上传
         */
        try {
            PutObjectResult result123 = amazonS3.putObject(new PutObjectRequest(fileBucket, key, file.getInputStream(), objectMetadata)
                    .withCannedAcl(CannedAccessControlList.BucketOwnerFullControl));   //配置文件访问权限 不能配置CannedAccessControlList.PublicRead
        } catch (IOException e) {
            e.printStackTrace();
        }
        //文件访问路径
        String address = endpoint + fileBucket + "/" + key;
        log.info("生成了》》》》》》》");
        log.info(address);
    }

    @Override
    public void download(String fileBucket, String key) {

        /**
         * 文件下载
         */
        try {
            S3Object o = amazonS3.getObject(fileBucket,key);
            S3ObjectInputStream s3is = o.getObjectContent();
            FileOutputStream fos = new FileOutputStream(new File("login.png"));
            byte[] read_buf = new byte[1024];
            int read_len = 0;
            while ((read_len = s3is.read(read_buf)) > 0) {
                fos.write(read_buf, 0, read_len);
            }
            s3is.close();
            fos.close();
        } catch (AmazonServiceException e) {
            System.err.println(e.getErrorMessage());
            System.exit(1);
        } catch (FileNotFoundException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        } catch (IOException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }

    /**
     * 验证文件名称：仅包含 汉字、字母、数字、下划线和点号
     *
     * @param fileName 文件名称
     * @return 返回true表示符合要求
     */
    private boolean validateFileName(String fileName) {
        String regex = "^[a-zA-Z0-9_\\u4e00-\\u9fa5_\\.]+$";
        return fileName.matches(regex);
    }
}
